#ifndef __EPSILON_INPUT__INPUT_H__
#define __EPSILON_INPUT__INPUT_H__

#include "../Epsilon/EpsilonInput/mouse.h"
#include "../Epsilon/EpsilonInput/keyboard.h"

#include "../Epsilon/types.h"
#include "../Epsilon/strings.h"

// Pending removal, subject to compiler build log verification...
#if 0
/* I think this code was put in place to fix an issue on OS X. */
/// The heck?!
#undef Button4
#undef Button5
#undef Button6
#undef Button7
#undef Button8
#endif

class eWindow;

class eInput_iListener {
public:
  virtual void OnMouse      (Epsilon::Mouse now, Epsilon::Mouse prev) { };

  virtual bool OnKeyPress   (Epsilon::Keyboard::Key key) { return false; };
  virtual bool OnKeyRelease (Epsilon::Keyboard::Key key) { return false; };
};

class eInput : public Epsilon::Keyboard_Listener,
               public Epsilon::Mouse_Listener
{
public:
             eInput (eWindow* win);
    virtual ~eInput (void);

public:
  class Mouse
  {
  public:
    enum Buttons {
      Left    = 0,
      Right   = 1,
      Middle  = 2,
      Button4 = 3,
      Button5 = 4,
      Button6 = 5,
      Button7 = 6,
      Button8 = 7
    };
  };

  class Keyboard
  {
  public:
  };

public:
    bool InitMouse     (void);        ///< Initialize the mouse input core
    bool KeyPressed    (int);         ///< Check whether a key is pressed
    bool Update        (void);        ///< Update all device states

    void ReleaseKey    (int);         ///< Hack

    void ShowCursor    (bool);        ///< Enable or disable the cursor
    void DrawCursor    (void);        ///< Draw mouse cursor
    void SetAttributes (bool, float); ///< Set cursor attributes

    /// Set new cursor position
    void SetCursorPos  (int, int);

    int GetDeltaX  (void); ///< Get relative movement (X)
    int GetDeltaY  (void); ///< Get relative movement (Y)
    int GetDeltaZ  (void); ///< Get Mouse Wheel Movement

    int GetCursorX (void); ///< Get cursor pos (X)
    int GetCursorY (void); ///< Get cursor pos (Y)

    int GetHotSpotX (void) { return hot_spot_x_; } ///< Get Hot Spot (X)
    int GetHotSpotY (void) { return hot_spot_y_; } ///< Get Hot Spot (Y)

    /// Set the Hot Spot (i.e. cursor pos before mouselook)
    void SetHotSpot (int x, int y) {
      hot_spot_x_ = x;
      hot_spot_y_ = y;
    }

    //bool CursorOnScreen (void); ///< Test if the cursor is on the screen (in the window)

    /// Check the mouse button (0 = Mouse Button 1, 1 = Mouse Button 2, ...)
    bool  IsMouseButtonDown (Mouse::Buttons, Epsilon::Mouse* = NULL);

    /// Resize the "virtual mousepad"
    void Resize (DWORD,DWORD);

    bool InstallListener   (eInput_iListener* pListener);
    bool UninstallListener (eInput_iListener* pListener);

    eWindow* GetWindow (void) { return window_; }

protected:
    bool OnKeyPress   (Epsilon::Keyboard::Key& key);
    bool OnKeyRelease (Epsilon::Keyboard::Key& key);

    bool OnButtonPress   (Epsilon::Mouse::Buttons::Button& button);
    bool OnButtonRelease (Epsilon::Mouse::Buttons::Button& button);

    bool OnMouseMove     (int x, int y);

private:
    eWindow*             window_;        ///< The parent window
    int                  screen_height_; ///< Cached Window Height
    int                  screen_width_;  ///< Cached Window Width

    /// Mouse State Structure
    Epsilon::Mouse       mouse_state_;   ///< A _COPY_ of the Mouse state.
    bool                 dirty_state_;   ///< Mouse state changed

    int                  cursor_pos_x_,  ///< Cursor Position (X)
                         cursor_pos_y_;  ///< Cursor Position (Y)

    /* The "Cursor Hot Spot" is the location of the cursor before
         mouselook, or something similar was activated...
         
         It stores a location (in client coordinates) to restore the cursor.
    */
    int                  hot_spot_x_,    ///< Cursor Hot Spot (X)
                         hot_spot_y_;    ///< Cursor Hot Spot (Y)

    bool                 invert_;        ///< Inverted y-axis 
    float                sensitivity_;   ///< Mouse Sensitivity
    bool                 show_cursor_;   ///< Show / Hide the cursor

    std::vector <eInput_iListener *>
                   listeners_;           ///< Input Listeners
};

class eTB_Input : public eInput_iListener, public eInput {
public:
  eTB_Input (eWindow* win) : eInput (win) {
    eInput::InstallListener (this);
  };

  ~eTB_Input (void) {
    eInput::UninstallListener (this);
  };

  virtual void OnMouse (Epsilon::Mouse now, Epsilon::Mouse prev) {
    // Do nothing, by default.
  }

  //virtual bool OnKeyPress   (Epsilon::Keyboard::Key& key);
  //virtual bool OnKeyRelease (Epsilon::Keyboard::Key& key);
};

#endif /* __EPSILON_INPUT__INPUT_H__ */
